﻿using System;
using System.Collections.Generic;
using System.Web.Security;
using AutoMapper;

namespace mForum.Services
{
    using mForum.Core.Common;
    using mForum.Core.Service;
    using mForum.Core.Messages;
    using mForum.Core.Messages.UserServiceMessages;
    using mForum.Core.Infrastructure;
    using mForum.Core.Infrastructure.Resource;
    using mForum.Core.DataTransferObject;
    using mForum.Core.Repository;
    using mForum.Infrastructure.NHibernate.Repository;
    using mForum.Domain.DomainObject;
    using mForum.Domain.Repository;
    using mForum.Resources;

    public class UserService : IUserService
    {
        private IUserRepository _userRepository;
        private IUnitOfWork _unitOfWork;

        public UserService(IUserRepository repository, IUnitOfWork unitOfWork)
        {
            Check.Argument.IsNotNull(repository, "repository");
            Check.Argument.IsNotNull(unitOfWork, "unitOfWork");

            _userRepository = repository;
            _unitOfWork = unitOfWork;
        }

        public LogOnResponse ValidateUser(LogOnRequest request)
        {
            Check.Argument.IsNotNull(request, "request");

            LogOnResponse response = new LogOnResponse();
            response.isValidated = false;

            User user = _userRepository.FindUserByUsername(request.LogOnDTO.Username);

            if (user == null)
                return response;

            if (user.Password == request.LogOnDTO.Password && user.isLockedOut == false)
            {
                user.LastLoginDate = DateTime.Now;
                _unitOfWork.Commit();

                response.isValidated = true;
                return response;
            }

            return response;
        }

        public RegisterResponse CreateUser(RegisterRequest request)
        {
            RegisterResponse response = new RegisterResponse();
            User userExists = _userRepository.FindUserByUsername(request.RegisterDTO.Username);

            if (userExists != null)
                throw new Exception(ResourceHelper.GetErrorMessage(ResourceKey.User.UserAleardyExists));

            User newUser = new User
            {
                Username = request.RegisterDTO.Username,
                Password = request.RegisterDTO.Password,
                Email = request.RegisterDTO.Email,
                PasswordQuestion = request.RegisterDTO.PasswordQuestion,
                PasswordAnswer = request.RegisterDTO.PasswordAnswer,
                isLockedOut = false,
                LastActivityDate = DateTime.Now,
                CreatedDate = DateTime.Now,
                LastLoginDate = DateTime.Now,
                LastLockedOutDate = DateTime.Now
            };

            _userRepository.Add(newUser);
            _unitOfWork.Commit();

            response.UserDTO = Mapper.Map<User, UserDTO>(newUser);

            return response;
        }

        public DeleteUserResponse DeleteUser(DeleteUserRequest request)
        {
            Check.Argument.IsNotNull(request, "request");

            DeleteUserResponse response = new DeleteUserResponse();

            User deletedUser = _userRepository.FindUserByUsername(request.Username);

            if (deletedUser == null)
                throw new ArgumentNullException(ResourceHelper.GetErrorMessage(ResourceKey.User.UserDoesNotExists));

            _userRepository.Delete(deletedUser);
            _unitOfWork.Commit();

            return response;
        }

        public GetUserByUsernameResponse GetUserByUsername(GetUserByUsernameRequest request)
        {
            Check.Argument.IsNotNull(request, "request");

            GetUserByUsernameResponse response = new GetUserByUsernameResponse();
            User user = _userRepository.FindUserByUsername(request.Username);

            if (user == null)
                throw new ArgumentNullException(ResourceHelper.GetErrorMessage(ResourceKey.User.UserDoesNotExists));

            response.UserDTO = Mapper.Map<User, UserDTO>(user);
            return response;

        }

        public ChangeQuestionAndAnswerResponse ChangeQuestionAndAnswer(ChangeQuestionAndAnswerRequest request)
        {
            Check.Argument.IsNotNull(request, "request");

            ChangeQuestionAndAnswerResponse response = new ChangeQuestionAndAnswerResponse();
            response.QuestionAndAnswerChanged = false;

            LogOnRequest logOnRequest = new LogOnRequest();
            logOnRequest.LogOnDTO = new LogOnDTO()
            {
                Username = request.ChangeQuestionAndAnswerDTO.Username,
                Password = request.ChangeQuestionAndAnswerDTO.Password
            };

            LogOnResponse logOnResponse = ValidateUser(logOnRequest);
            if (!logOnResponse.isValidated)
                return response;

            User user = _userRepository.FindUserByUsername(request.ChangeQuestionAndAnswerDTO.Username);
            if (user == null)
                return response;

            user.PasswordQuestion = request.ChangeQuestionAndAnswerDTO.NewQuestion;
            user.PasswordAnswer = request.ChangeQuestionAndAnswerDTO.NewAnswer;

            _unitOfWork.Commit();

            response.QuestionAndAnswerChanged = true;
            return response;
        }

        public GetNumberOfUsersOnlineResponse GetNumberOfUsersOnline(GetNumberOfUsersOnlineRequest request)
        {
            GetNumberOfUsersOnlineResponse response = new GetNumberOfUsersOnlineResponse()
            {
                NumberOfUsersOnline = _userRepository.CountNumberOfOnlineUsers()
            };

            return response;
        }

        public ResetPasswordResponse ResetPassword(ResetPasswordRequest request)
        {
            Check.Argument.IsNotNull(request, "request");

            ResetPasswordResponse response = new ResetPasswordResponse();

            User user = _userRepository.FindUserByUsername(request.ResetPasswordDto.Username);

            if (user == null)
                throw new ArgumentException(ResourceHelper.GetErrorMessage(ResourceKey.User.UserDoesNotExists));

            if (user.PasswordAnswer != request.ResetPasswordDto.QuestionAnswer)
                throw new ArgumentException(ResourceHelper.GetErrorMessage(ResourceKey.User.PasswordDoesNotMatch));

            string newPassword = Membership.GeneratePassword(10, 0);

            user.Password = newPassword;
            _unitOfWork.Commit();

            return response;
        }

        public LockOrUnlockUserResponse LockOrUnlockUser(LockOrUnlockUserRequest request)
        {
            Check.Argument.IsNotNull(request, "request");

            LockOrUnlockUserResponse response = new LockOrUnlockUserResponse();

            User user = _userRepository.FindUserByUsername(request.LockOrUnlockUserDTO.Username);

            if (user == null)
                throw new ArgumentException(ResourceHelper.GetErrorMessage(ResourceKey.User.UserDoesNotExists));

            if (request.LockOrUnlockUserDTO.IsLocked == true)
            {
                user.isLockedOut = true;
                user.LastLockedOutDate = DateTime.Now;
            }
            else
                user.isLockedOut = false;

            _unitOfWork.Commit();

            return response;
        }


        public UpdateLastActivityResponse UpdateLastActivity(UpdateLastActivityRequest request)
        {
            Check.Argument.IsNotNull(request, "request");

            UpdateLastActivityResponse response = new UpdateLastActivityResponse();

            User user = _userRepository.FindUserByUsername(request.Username);

            if(user == null)
                throw new ArgumentException(ResourceHelper.GetErrorMessage(ResourceKey.User.UserDoesNotExists));

            user.LastActivityDate = DateTime.Now;

            _unitOfWork.Commit();

            return response;
        }
    }
}
